package com.lyf.auth.service.impl;

import com.lyf.auth.constant.ResponseCodeEnum;
import com.lyf.auth.dataDao.AuthConfigurationDao;
import com.lyf.auth.domain.pojo.AuthConfiguration;
import com.lyf.auth.domain.pojo.JWKInfo;
import com.lyf.auth.domain.pojo.ScopeSupportApiListAccess;
import com.lyf.auth.domain.request.AddClientScopeRequestBody;
import com.lyf.auth.domain.request.AddScopeRequestBody;
import com.lyf.auth.domain.request.LoginRequestBody;
import com.lyf.auth.domain.response.CheckTokenResponse;
import com.lyf.auth.domain.response.LoginResponseBody;
import com.lyf.auth.domain.settings.WhiteListSettings;
import com.lyf.auth.service.AuthProviderService;
import com.lyf.auth.service.EncryptService;
import com.lyf.auth.utils.TimeUtil;
import com.lyf.auth.utils.UUIDUtil;
import com.lyf.common.api.CommonResult;
import com.lyf.common.utils.JacksonUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class AuthProviderServiceImpl implements AuthProviderService {
   private static final Logger logger = LoggerFactory.getLogger(AuthProviderServiceImpl.class);
   @Autowired
   private EncryptService encryptService;
   @Autowired
   private AuthConfigurationDao authConfigurationDao;
   @Value("${module-conf.kid}")
   private String kid;
   @Value("${module-conf.alg}")
   private String alg;
   @Value("${module-conf.token-use}")
   private String tokenUse;
   @Value("${module-conf.token-expires-in}")
   private String tokenExpiresIn;
   @Value("${module-conf.token-type}")
   private String tokenType;
   @Value("${module-conf.token-iss}")
   private String tokenIss;
   @Autowired
   private WhiteListSettings whiteListSettings;
   private static final String ADMIN_SCOPE = "cvp.com/scope/admin";
   @Override
   public LoginResponseBody generateJWTToken(LoginRequestBody loginRequestBody) {
      RSAPrivateKey privateKey = null;

      try {
         privateKey = encryptService.loadPrivateKeyFromConf();
      } catch (Exception var10) {
         throw new RuntimeException("get rsa private key error:" + var10.getMessage());
      }

      try {
         Map<String, Object> headers = new HashMap();
         headers.put("kid", kid);
         headers.put("alg", alg);
         Map<String, Object> claims = new HashMap();
         claims.put("sub", loginRequestBody.getClientId());
         claims.put("token_use", tokenUse);
         claims.put("scope", loginRequestBody.getScope());
         Long nowTime = TimeUtil.getNowTimeSeconds();
         claims.put("iat", nowTime);
         claims.put("exp", nowTime + Long.valueOf(tokenExpiresIn));
         String jwtId = UUIDUtil.getLowerCaseUUID();
         claims.put("jti", jwtId);
         claims.put("iss", StringUtils.substringBefore(loginRequestBody.getScope(), "/"));
         String token = Jwts.builder().setHeader(headers).setClaims(claims).signWith(SignatureAlgorithm.RS256, privateKey).compact();
         logger.info("header={}, payload={}, token={}", new Object[]{headers.toString(), claims.toString(), token});
         LoginResponseBody loginResponseBody = new LoginResponseBody();
         loginResponseBody.setAccessToken(token);
         loginResponseBody.setExpiresIn(Long.valueOf(tokenExpiresIn));
         loginResponseBody.setTokenType(tokenType);
         return loginResponseBody;
      } catch (Exception var9) {
         logger.info("build JWT token error:" + var9.getMessage());
         throw new RuntimeException(var9);
      }
   }
   @Override
   public AuthConfiguration registerAuthService(String comment, Set<String> owner)  {
      return authConfigurationDao.registerClientAccount(comment, owner);
   }
   @Override
   public CommonResult checkToken(String url, String token) {
      CommonResult checkTokenResponseBody = new CommonResult(ResponseCodeEnum.RESPONSE_CODE_SUCCESS.getCode(),"success");

      try {
         String[] strings = token.split("\\.");
         if (strings.length != 3) {
            throw new RuntimeException("invalid token");
         }

         String base64Header = strings[0];
         byte[] bytes = new byte[0];

         try {
            bytes = Base64.getDecoder().decode(base64Header);
         } catch (Exception var25) {
            var25.printStackTrace();
         }

         String jsonHeader = new String(bytes, "utf-8");
         String kid = JacksonUtil.getTreeNode(jsonHeader, "kid").asText();
         logger.info("kid:{}", kid);
         String publicKeyStr = "";
         List<JWKInfo> jwkInfoList = encryptService.getJWKs().getKeys();
         Iterator var11 = jwkInfoList.iterator();

         while(var11.hasNext()) {
            JWKInfo jwkInfo = (JWKInfo)var11.next();
            if (jwkInfo.getKid().equals(kid)) {
               publicKeyStr = jwkInfo.getPublicKey();
            }
         }

         if (publicKeyStr.isEmpty()) {
            throw new RuntimeException("invalid kid");
         }

         RSAPublicKey rsaPublicKey = encryptService.loadPublicKeyFromString(publicKeyStr);
         Claims claims = (Claims)Jwts.parser().setSigningKey(rsaPublicKey).parseClaimsJws(token).getBody();
         Long nowTime = TimeUtil.getNowTimeSeconds();
         Integer exp = (Integer)claims.get("exp");
         Integer iat = (Integer)claims.get("iat");
         if (nowTime > (long)exp || nowTime < (long)iat) {
            logger.info("token expire or not effect");
            throw new RuntimeException("token expire or not effect");
         }

         Boolean isMatch = false;
         String scope = (String)claims.get("scope");
         if (scope.equals("cvp.com/scope/admin")) {
            if (!whiteListSettings.getWhiteList().containsKey("cvp.com/scope/admin")) {
               logger.info("lack white scope conf :{}", "cvp.com/scope/admin");
               throw new RuntimeException("lack white scope conf :cvp.com/scope/admin");
            }

            Set<String> whiteClientId = (Set)whiteListSettings.getWhiteList().get("cvp.com/scope/admin");
            String clientId = claims.getSubject();
            if (whiteClientId.contains(clientId)) {
               isMatch = true;
            }
         }

         if (!isMatch) {
            String subject = claims.getSubject();
            Set<String> apiListSet = authConfigurationDao.getScopeSupportApiList(scope, subject);
            logger.info("scope:{}, apiListSet:{}", scope, apiListSet);
            if (apiListSet == null) {
               checkTokenResponseBody.setCode(ResponseCodeEnum.RESPONSE_CODE_TOKEN_NO_PERMISSION.getCode());
               checkTokenResponseBody.setMsg("scope no bind apiList");
               return checkTokenResponseBody;
            }

            Iterator iterator = apiListSet.iterator();

            while(iterator.hasNext()) {
               String regEx = (String)iterator.next();
               Pattern pattern = Pattern.compile(regEx);
               Matcher matcher = pattern.matcher(url);
               boolean result = matcher.find();
               if (result) {
                  isMatch = true;
                  break;
               }
            }
         }

         if (isMatch) {
            checkTokenResponseBody.setData(claims);
            checkTokenResponseBody.setCode(ResponseCodeEnum.RESPONSE_CODE_SUCCESS.getCode());
            checkTokenResponseBody.setMsg("SUCCESS");
         } else {
            checkTokenResponseBody.setCode(ResponseCodeEnum.RESPONSE_CODE_TOKEN_NO_PERMISSION.getCode());
            checkTokenResponseBody.setMsg("Token no Access to the interface");
         }
      } catch (ExpiredJwtException var26) {
         checkTokenResponseBody.setCode(ResponseCodeEnum.RESPONSE_CODE_TOKEN_TIME_EXPIRED.getCode());
         checkTokenResponseBody.setMsg("Token expired");
      } catch (Exception var27) {
         logger.info("checkToken error:" + var27);
         checkTokenResponseBody.setCode(ResponseCodeEnum.RESPONSE_CODE_TOKEN_INVALID.getCode());
         checkTokenResponseBody.setMsg("Token invalid");
      }

      return checkTokenResponseBody;
   }
   @Override
   public void addScope(AddScopeRequestBody addScopeRequestBody)  {
      ScopeSupportApiListAccess scopeSupportApiList = new ScopeSupportApiListAccess();
      scopeSupportApiList.setScope(addScopeRequestBody.getScope());
      scopeSupportApiList.setApiList(addScopeRequestBody.getApiList());
      authConfigurationDao.addScopeSupportApiList(scopeSupportApiList);
   }
   @Override
   public List<ScopeSupportApiListAccess> getAllScopeInfo()  {
      return authConfigurationDao.getAllScopeInfoFromDB();
   }
   @Override
   public AuthConfiguration addClientScope(AddClientScopeRequestBody request)  {
      AuthConfiguration clientInfo = authConfigurationDao.getClientInfo(request.getClientId());
      if (clientInfo == null) {
         throw new RuntimeException("clientId is invalid");
      } else {
         clientInfo.getScopes().addAll(request.getScope());
         clientInfo.setUpdateTime(new Date());
         authConfigurationDao.setClientScope(request.getClientId(), clientInfo.getScopes());
         return clientInfo;
      }
   }
   @Override
   public AuthConfiguration setClientScope(AddClientScopeRequestBody request)  {
      authConfigurationDao.setClientScope(request.getClientId(), request.getScope());
      AuthConfiguration result = authConfigurationDao.getClientInfo(request.getClientId());
      result.setScopes(request.getScope());
      return result;
   }
   @Override
   public AuthConfiguration getClientInfo(String clientId)  {
      return authConfigurationDao.getClientInfo(clientId);
   }
}
